package com.shuwen.gcdj.common.util.http;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.shuwen.gcdj.common.constant.Constants;
import com.shuwen.gcdj.common.util.string.StringUtil;
import com.shuwen.gcdj.common.util.time.TimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.util.EntityUtils;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.Map;

/**
 * 用户中心http封装
 */
@Slf4j
public class UserHttpUtil {

    private static final String STARFISH_PUSH_TOKEN = "gAAAAABXB1xu0HvVWLKC9xgU4QsP5J80OCOU1K0Nt1YJ-CrChgOS4ifweQpbiXGEZYF-FHNxgH3YqqEA1VEPKmPfXFLYuXUAitYU2zzu63f5WJJAC9rtfao=";

    private static final String UTF_8 = "UTF-8";

    private UserHttpUtil() {
        throw new IllegalStateException("Utility class");
    }

    /**
     * sendPost
     *
     * @param url  String
     * @param json JSONObject
     * @return String
     */
    public static ResponseEntity<String> sendPost(String url, JSONObject json) {
        HttpHeaders headers = HttpUtil.getJsonHttpHeaders();
        return sendPost(headers, url, json.toJSONString());
    }

    /**
     * sendPost
     *
     * @param url  String
     * @param json String
     * @return String
     */
    public static ResponseEntity<String> sendPost(String url, String json) {
        HttpHeaders headers = HttpUtil.getJsonHttpHeaders();
        return sendPost(headers, url, json);
    }

    /**
     * sendPost
     *
     * @param headersMap Map
     * @param url        String
     * @param json       JSONObject
     * @return String
     */
    public static ResponseEntity<String> sendPost(Map<String, String> headersMap, String url, JSONObject json) {
        HttpHeaders headers = createHeaders(headersMap);
        return sendPost(headers, url, json.toJSONString());
    }

    /**
     * sendPost
     *
     * @param headersMap Map
     * @param url        String
     * @param json       String
     * @return String
     */
    public static ResponseEntity<String> sendPost(Map<String, String> headersMap, String url, String json) {
        HttpHeaders headers = createHeaders(headersMap);
        return sendPost(headers, url, json);
    }

    /**
     * sendPost
     *
     * @param headers HttpHeaders
     * @param url     String
     * @param json    String
     * @return String
     */
    public static ResponseEntity<String> sendPost(HttpHeaders headers, String url, String json) {
        HttpEntity<String> httpEntity = new HttpEntity<>(json, headers);
        return HttpUtil.exchange(url, HttpMethod.POST, httpEntity);
    }

    /**
     * sendPut
     *
     * @param url  String
     * @param json JSONObject
     * @return String
     */
    public static ResponseEntity<String> sendPut(String url, JSONObject json) {
        HttpHeaders headers = HttpUtil.getJsonHttpHeaders();
        return sendPut(headers, url, json.toJSONString());
    }

    /**
     * sendPut
     *
     * @param url  String
     * @param json String
     * @return String
     */
    public static ResponseEntity<String> sendPut(String url, String json) {
        HttpHeaders headers = HttpUtil.getJsonHttpHeaders();
        return sendPut(headers, url, json);
    }

    /**
     * sendPut
     *
     * @param headersMap Map
     * @param url        String
     * @param json       JSONObject
     * @return String
     */
    public static ResponseEntity<String> sendPut(Map<String, String> headersMap, String url, JSONObject json) {
        HttpHeaders headers = createHeaders(headersMap);
        return sendPut(headers, url, json.toJSONString());
    }

    /**
     * sendPut
     *
     * @param headersMap Map
     * @param url        String
     * @param json       String
     * @return String
     */
    public static ResponseEntity<String> sendPut(Map<String, String> headersMap, String url, String json) {
        HttpHeaders headers = createHeaders(headersMap);
        return sendPut(headers, url, json);
    }

    /**
     * sendPut
     *
     * @param headers HttpHeaders
     * @param url     String
     * @param json    String
     * @return String
     */
    public static ResponseEntity<String> sendPut(HttpHeaders headers, String url, String json) {
        HttpEntity<String> httpEntity = new HttpEntity<>(json, headers);
        return HttpUtil.exchange(url, HttpMethod.PUT, httpEntity);
    }

    /**
     * sendGet
     *
     * @param url String
     * @return String
     */
    public static ResponseEntity<String> sendGet(String url) {
        HttpHeaders headers = HttpUtil.getJsonHttpHeaders();
        return sendGet(headers, url);
    }

    /**
     * sendGet
     *
     * @param headersMap Map
     * @param url        String
     * @return String
     */
    public static ResponseEntity<String> sendGet(Map<String, String> headersMap, String url) {
        HttpHeaders headers = createHeaders(headersMap);
        return sendGet(headers, url);
    }

    /**
     * sendGet
     *
     * @param headers HttpHeaders
     * @param url     String
     * @return String
     */
    public static ResponseEntity<String> sendGet(HttpHeaders headers, String url) {
        HttpEntity<String> httpEntity = new HttpEntity<>(headers);
        return HttpUtil.exchange(url, HttpMethod.GET, httpEntity);
    }

    /**
     * sendDelete
     *
     * @param url  String
     * @param json JSONObject
     * @return String
     */
    public static ResponseEntity<String> sendDelete(String url, JSONObject json) {
        HttpHeaders headers = HttpUtil.getJsonHttpHeaders();
        return sendDelete(headers, url, json.toJSONString());
    }

    /**
     * sendDelete
     *
     * @param url  String
     * @param json String
     * @return String
     */
    public static ResponseEntity<String> sendDelete(String url, String json) {
        HttpHeaders headers = HttpUtil.getJsonHttpHeaders();
        return sendDelete(headers, url, json);
    }

    /**
     * sendDelete
     *
     * @param headersMap Map
     * @param url        String
     * @param json       JSONObject
     * @return String
     */
    public static ResponseEntity<String> sendDelete(Map<String, String> headersMap, String url, JSONObject json) {
        HttpHeaders headers = createHeaders(headersMap);
        return sendDelete(headers, url, json.toJSONString());
    }

    /**
     * sendDelete
     *
     * @param headersMap Map
     * @param url        String
     * @param json       String
     * @return String
     */
    public static ResponseEntity<String> sendDelete(Map<String, String> headersMap, String url, String json) {
        HttpHeaders headers = createHeaders(headersMap);
        return sendDelete(headers, url, json);
    }

    /**
     * sendDelete
     *
     * @param headers HttpHeaders
     * @param url     String
     * @param json    String
     * @return String
     */
    public static ResponseEntity<String> sendDelete(HttpHeaders headers, String url, String json) {
        HttpEntity<String> httpEntity = new HttpEntity<>(json, headers);
        return HttpUtil.exchange(url, HttpMethod.DELETE, httpEntity);
    }

    /**
     * createHeaders
     *
     * @param headers Map
     * @return HttpHeaders
     */
    public static HttpHeaders createHeaders(Map<String, String> headers) {
        HttpHeaders headers2 = new HttpHeaders();
        for (Map.Entry<String, String> entry : headers.entrySet()) {
            headers2.add(entry.getKey(), entry.getValue());
        }
        headers2.setContentType(new MediaType(Constants.APPLICATION, "json", StandardCharsets.UTF_8));
        return headers2;
    }

    /**
     * sendTextPushMsg2Starfish
     *
     * @param url  String
     * @param json String
     */
    public static void sendTextPushMsg2Starfish(String url, String json) {
        if (StringUtils.isNotBlank(json)) {
            HttpHeaders headers = new HttpHeaders();
            headers.set("Token", STARFISH_PUSH_TOKEN);
            headers.setContentType(new MediaType(Constants.APPLICATION, "json", StandardCharsets.UTF_8));
            headers.set("Accept", "application/json");
            ResponseEntity<String> apiResponse = sendPost(headers, url, json);
            log.debug("sendTextPushMsg2Starfish response:" + apiResponse + "@@@@@ json body:" + apiResponse.getBody());
        }
    }

    /**
     * sslGet
     *
     * @param url String
     * @return String
     */
    public static String sslGet(String url) {
        String responseBody = null;
        HttpGet get = new HttpGet(url);
        HttpClient httpclient = getSslClient();
        try {
            responseBody = httpclient.execute(get, getResponseHandler());
        } catch (IOException e) {
            log.error("httpclient.execute() error:", e);
        }
        return responseBody;
    }

    /**
     * sslPost
     *
     * @param entity HttpEntity
     * @param url    String
     * @return String
     */
    public static String sslPost(org.apache.http.HttpEntity entity, String url) {
        String responseBody = null;
        if (entity != null) {
            HttpPost post = new HttpPost(url);
            post.setEntity(entity);
            HttpClient httpclient = getSslClient();
            try {
                responseBody = httpclient.execute(post, getResponseHandler());
            } catch (Exception e) {
                log.error("httpclient.execute() error:", e);
            }
        }
        return responseBody;
    }

    private static HttpClient getSslClient() {
        try {
            SSLContext ctx = SSLContext.getInstance("TLSv1.2");
            X509TrustManager tm = new X509TrustManager() {
                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return new X509Certificate[]{};
                }

                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                    if (chain == null || authType == null) {
                        throw new CertificateException();
                    }
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType)
                        throws CertificateException {
                    if (chain == null || authType == null) {
                        throw new CertificateException();
                    }
                }
            };
            ctx.init(null, new TrustManager[]{tm}, null);
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(ctx,
                    new String[]{"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}, null, new NoopHostnameVerifier());
            Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", PlainConnectionSocketFactory.getSocketFactory())
                    .register("https", sslConnectionSocketFactory).build();
            try (PoolingHttpClientConnectionManager mgr = new PoolingHttpClientConnectionManager(registry)) {
                return HttpClientBuilder.create().setConnectionManager(mgr).build();
            }
        } catch (Exception e) {
            log.error("getSslClient() error:", e);
            return HttpClients.createDefault();
        }
    }

    private static ResponseHandler<String> getResponseHandler() {
        return new ResponseHandler<String>() {
            @Override
            public String handleResponse(final HttpResponse response) throws IOException {
                int status = response.getStatusLine().getStatusCode();
                String result = null;
                if (status >= 200 && status <= 500 && response.getEntity() != null) {
                    result = EntityUtils.toString(response.getEntity(), UTF_8);
                }
                return result;
            }
        };
    }

    /**
     * 从响应体中获取数组
     *
     * @param response response
     */
    public static JSONArray getArrayFromResponse(ResponseEntity<String> response) {
        if (response.getStatusCodeValue() < 200 || response.getStatusCodeValue() >= 300) {
            return new JSONArray();
        }
        String body = response.getBody();
        if (StringUtils.isBlank(body) || "{}".equals(body)) {
            return new JSONArray();
        }
        return JSON.parseArray(body);
    }

    /**
     * 从响应体中获取数组
     *
     * @param response response
     */
    public static JSONObject getObjectFromResponse(ResponseEntity<String> response) {
        if (response.getStatusCodeValue() < 200 || response.getStatusCodeValue() >= 300) {
            return null;
        }
        String body = response.getBody();
        if (StringUtils.isBlank(body) || "{}".equals(body)) {
            return null;
        }
        return JSON.parseObject(body);
    }

    /**
     * 获取AK/SK加密方式信息头
     *
     * @param accessKey accessKey
     * @param secretKey secretKey
     */
    public static HttpHeaders getAkSkHeaders(String accessKey, String secretKey) {
        // 获取当前时间戳
        String timestamp = TimeUtil.getCurrentUnixTime();
        // 获取32位随机数
        String nonce = StringUtil.getNonce();
        String signature = DigestUtils.sha256Hex(accessKey + secretKey + nonce + timestamp);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(new MediaType(Constants.APPLICATION, "json", StandardCharsets.UTF_8));
        headers.add("Source", "705");
        headers.add("accesskey", accessKey);
        headers.add("nonce", nonce);
        headers.add("timestamp", timestamp);
        headers.add("signature", signature);
        return headers;
    }
}
